# -*- coding: UTF-8 -*-
import json, jsonpath, requests, traceback
from InterfaceAuto.commonalKeys import syspublic
from configuration import Encrypt
from configuration.logger import logger


class HTTP():
    """
      interface keyword
      creator: Mr.Dou

    """

    def __init__(self, writer):

        self.session = requests.session()         # creat session mangers
        self.url = ''                             # project interface 基本地址
        self.result = None                        # 保存请求结果
        self.jsonRes = None                       # 保存json解析后的字典
        self.row = 0                              # 记录关键字运行时,写入Excel的行
        self.writer = writer                      # 写入结果的对象
        self.session.headers[
            'user-agent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36'

    def set_url(self, url):
        """
         设置项目接口基本地址
        :param url: 基本地址
        :return:
        """
        try:
            if url is None or url == '':
                url = ''
            self.url = url
            self.__writerexcel(True, self.url)
            return True
        except Exception as e:
            self.__writerexcel(False, traceback.format_exc())
            print(traceback.format_exc())
            logger.exception(e)

    def post_data(self, path, params):
        """
        data字典形式传入键值对参数
        :param path: 接口地址
        :param params: data dict 参数字典
        :return:  True or false
        """

        if params is None or params == "":
            params = None

        if path is None or path == '':
            self.__writerexcel(False, "path错误")
            return False

        # 添加关联
        params = self.__getrelations(params)
        # 加密参数
        params = self.__use_encrypt(params)
        # 把url参数转为dict
        params = self.__transformdata(params)

        if not path.startswith("http"):
            path = self.url + "/" + path

        try:
            self.result = self.session.post(path, data=params)
            print(self.result.text)
        except Exception as e:
            self.result = None

        # print(self.result.text)
        try:
            # 如果返回的是json字符串就转成dict
            result_text = self.result.text
            result_text = result_text[result_text.find('{'):result_text.rfind('}') + 1]
            self.jsonRes = json.loads(result_text)
            print(str(self.jsonRes))
            self.__writerexcel(True, self.result.text)
        except Exception as e:
            # UnitTest报告输入结果详细一点
            print(self.result.text)
            print(traceback.format_exc())
            self.jsonRes = None
            if self.result is None:
                self.__writerexcel(False, None)
            else:
                self.__writerexcel(False, "返回的不是json格式: " + self.result.text)
            logger.exception(e)
        return True

    def post_nodata(self, path, params):
        """
        不是以dict形式传参
        :param path: 接口地址
        :param params: data 是字符串形式
        :return:  True or false
        """

        # 参数处理
        if params is None or params == "":
            params = None
        # 路径处理
        if path is None or path == '':
            self.__writerexcel(False, "path错误")
            return False

        # 添加关联
        params = self.__getrelations(params)

        if not path.startswith("http"):
            path = self.url + "/" + path

        try:
            self.result = self.session.post(path, data=params)
        except Exception as e:
            self.result = None
        print(self.result.text)
        try:
            # 如果返回的是json字符串就转成dict
            resulttext = self.result.text
            resultstext = resulttext[resulttext.find('{'):resulttext.rfind('}') + 1]
            self.jsonRes = json.loads(resultstext)
            print(self.jsonRes)
            self.__writerexcel(True, self.result.text)
        except Exception as e:
            # UnitTest报告输入结果详细一点
            print(self.result.text)
            print(traceback.format_exc())
            self.jsonRes = None
            if self.result is None:
                self.__writerexcel(False, None)
            else:
                self.__writerexcel(False, self.result.text)
            logger.exception(e)

    def post_json(self, path, params):
        """
        Json字符串形式传入键值对参数
        :param path: 接口地址
        :param params: Json字符串传入参数
        :return:  True or false
        """

        if params is None or params == "":
            params = None

        if path is None or path == '':
            self.__writerexcel(False, "path错误")
            return False

        # 添加关联
        params = self.__getrelations(params)
        # 把字符串转成dict
        params=json.loads(params)

        if not path.startswith("http"):
            path = self.url + "/" + path

        self.result = self.session.post(path, json=params)
        # print(self.result.text)
        try:
            # 如果返回的是json字符串就转成dict
            self.jsonRes = json.loads(self.result.text)
            print(str(self.jsonRes))
            self.__writerexcel(True, self.jsonRes)
        except Exception as e:
            # UnitTest报告输入结果详细一点
            print(self.result.text)
            print(traceback.format_exc())
            self.jsonRes = None
            if self.jsonRes is None:
                self.__writerexcel(False, None)
            else:
                self.__writerexcel(False, self.result.text)
            logger.exception(e)

    def get(self, path, params=None):
        """
        data字典形式传入键值对参数
        :param path: 接口地址
        :param params: data dict 参数字典
        :return:  True or false
        """
        # 对传入参数的处理
        if params is None or params == "":
            params = None

        # 对path进行处理
        if path is None or path == '':
            self.__writerexcel(False, "path错误")
            return False

        # 添加关联
        params = self.__getrelations(params)

        if not path.startswith("http"):
            path = self.url + "/" + path
        try:
            self.result = self.session.get(path + "?" + params)
            print(self.result)
        except Exception as e:
            self.result = None
        # print(self.result.text)
        try:
            # 如果返回的是json字符串就转成dict
            resulttext = self.result.text
            resulttext = resulttext[resulttext.find('{'):resulttext.rfind('}') + 1]
            self.jsonRes = json.loads(resulttext)
            print(self.jsonRes)
            self.__writerexcel(True, self.result.text)
        except Exception as e:
            logger.exception(e)
            self.jsonRes = None
            if self.result is None:
                self.__writerexcel(False, None)
            else:
                self.__writerexcel(False, self.result.text)
        return True

    def add_header(self, key, value):
        """
        往请求头里面添加一个键值对
        :param key: headkey
        :param value: headvalue
        :return:
        """
        try:
            value = self.__getrelations(value)
            self.session.headers[key] = value
            self.__writerexcel(True, self.session.headers)
        except Exception as e:
            self.__writerexcel(False, traceback.format_exc())
            logger.exception(e)

    def remove_header(self, key):
        """
        删除请求头
        :param key: 需要删除的key
        :return:  True or False
        """
        try:
            key = self.session.headers.pop(key)
            self.__writerexcel(True, key)
        except Exception as e:
            self.__writerexcel(False, traceback.format_exc())
            logger.exception(e)

    def save_params(self, jsonkey, paramname):
        """
        保存关联，从jsonRes里面保存某个键的值，用来关联
        :param jsonkey:  需要提取的键名
        :param paramname: 保存的参数名
        :return: True or False
        """
        try:
            value = str(jsonpath.jsonpath(self.jsonRes, jsonkey)[0])
        except Exception as e:
            value = None
            self.__writerexcel(False, traceback.format_exc())
            logger.exception(e)
        # 保存取到的jsonkey的值到全局变量中
        syspublic.relations[paramname] = value
        self.__writerexcel(True, syspublic.relations)

        return True

    def __transformdata(self, params):
        """
        url参数转为dict  例：username=k&password=1 转为 username ：k, password ：1
        这样在Excel里面就可以用username=k&password=1 传参了
        :param params: 需要转换的参数
        :return: 转换后的dict
        """
        if params is None:
            return None
        # 定义一个dict，用来保存转换后的参数
        param = {}
        p = params.split('&')
        for keyvalue in p:
            index = keyvalue.find('=')
            if index >= 0:
                key = keyvalue[0:index]
                value = keyvalue[index + 1:]
                param[key] = value
            else:
                param[keyvalue] = ''
        return param

    def __getrelations(self, params):
        """
        使用关联
        :param params: 需要关联的参数
        :return:  关联后的字符串
        """
        if params is None:
            return None

        for key in syspublic.relations.keys():
            params = params.replace('{' + key + '}', str(syspublic.relations[key]))
        return params

    def assert_equal(self, key, expectparams):
        """
        断言Json结果里面某个键的值是否和期望值一样
        :param key: jsonKey 需要断言的字段
        :param expectparams: 期望值
        :return:
        """
        if self.jsonRes is None:
            self.__writerexcel(False, 'jsonRes为空')
            print(self.jsonRes)
            return False

        expectparams = self.__getrelations(expectparams)
        try:
            actual = str(jsonpath.jsonpath(self.jsonRes, key)[0])
            if actual == str(expectparams):
                self.__writerexcel(True, actual)
                return True
            else:
                self.__writerexcel(False, actual)
                print("预期结果：" + str(expectparams))
                print("实际结果：" + str(actual))
                return False
        except Exception as e:
            # 处理键不存在的情况
            self.__writerexcel(False, traceback.format_exc())
            print(traceback.format_exc())
            logger.exception(e)
            return False

    def assert_equals(self, jsons):
        """
        断言Json结果，多个键值对是否相等
        :param jsons: 传入你需要比较多个键值对的字符串
        :return:
        """
        if self.jsonRes is None:
            self.__writerexcel(False, 'jsonRes为空')
            return False
        # 判断传入的是否是json字符串
        try:
            jsons = json.loads(jsons)
        except Exception as e:
            self.__writerexcel(False, traceback.format_exc())
            self.__writerexcel(False, '传入参数不是json')
            logger.exception(e)
            return False

        try:
            for key in jsons.key():
                # 只要有一个键值对不相等，就失败
                # if not str(self.jsonRes[key]) == str(jsons[key]):
                #   return False
                value = str(jsonpath.jsonpath(self.jsonRes, key)[0])
                if value == str(jsons[key]):
                    self.__writerexcel(True, self.jsonRes)
                    pass
                else:
                    self.__writerexcel(False, self.jsonRes)
                    return False
            return True
        except Exception as e:
            self.__writerexcel(False, traceback.format_exc())
            return False

    def assert_contains(self, value):
        """
        断言json返回中是否包含某个值
        :param value: 期望包含的值
        :return: True or False
        """
        try:
            result = str(self.result.text)
            # 如果返回结果为空
        except Exception as e:
            return False
        value = self.__getrelations(value)
        if result.__contains__(str(value)):
            self.__writerexcel(True, self.result.text)
            return True

        else:
            self.__writerexcel(False, self.result.text)
            return False

    def __writerexcel(self, status, msg):
        """
        写入关键字运行结果
        :param status: 运行状态
        :param msg: 实际结果

        """
        if status is True:
            self.writer.write(self.row, 7, "PASS", 3)
        else:
            self.writer.write(self.row, 7, "FAIL", 2)
        self.writer.write(self.row, 8, str(msg))

    def __use_encrypt(self, params):
        """
        替换加密后的字符串
        :param s: 需要加密的字符串
        :return: 加密后的字符串
        """
        # 递归的思维，当字符串里面既有[,又有]的时候
        # 反复的执行如下替换
        if params is None:
            return ''
        # 参数用[]括起来的就代表加密
        elif params.find('[') >= 0 and params.find(']') >= 0:
            # 截取中括号里面的参数
            en_s = params[params.find('[') + 1:params.find(']')]
            # 加密
            en_s1 = Encrypt.encrypt(en_s)
            params = params.replace('[' + en_s + ']', en_s1)
            return self.__use_encrypt(params)
        else:
            return params
